package org.scut.smartgeometry.view.identify_system;

import android.util.Log;

import org.scut.smartgeometry.utils.Utils;
import org.scut.smartgeometry.view.identify_system.shape.SGCircle;
import org.scut.smartgeometry.view.identify_system.shape.SGLine;
import org.scut.smartgeometry.view.identify_system.shape.SGShape;
import org.scut.smartgeometry.view.identify_system.shape.SGTriangle;
import org.scut.smartgeometry.view.identify_system.shape.inf.SGQuadrangle;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 13-7-11.
 */
public class ShapeIdentifySystem {

    private static ShapeIdentifySystem shapeIdentifySystem;

    private List<SGShape> shapes;

    private List<SGShape> removeShapes;


    private ShapeIdentifySystem(){
        shapes = new ArrayList<SGShape>();
        removeShapes = new ArrayList<SGShape>();
    }

    public static ShapeIdentifySystem getSingleton(){
        if(shapeIdentifySystem == null) shapeIdentifySystem = new ShapeIdentifySystem();

        return shapeIdentifySystem;
    }


    public void shapeIdentify(List<SGPoint> points, SGPath path){

        int points_num = points.size();
        SGShape shape = null;

        Log.i("hbb", "points_num =   " + points_num);

        float[] angle = getAngles(points);

        if(points_num < 6){

            List<SGPoint> vertexes = new ArrayList<SGPoint>();
            vertexes.add(points.get(0));
            vertexes.add(points.get(points_num - 1));
            shape = new SGLine(vertexes, path, vertexes);

        }
        else if( (shape = isCircle(points, angle, path)) != null ){
        }
        else if( (shape = isTriangle(points, angle, path)) != null ){
        }
        else if( (shape = isQuadrangle(points, angle, path)) != null ){
        }
        else if( (shape = isLine(points, angle, path)) != null ){
        }

        if(shape != null){
            shape.draw();
        }

        shapes.add(shape);

    }




    public void redo(){
        int size = removeShapes.size();
        if(size == 0) return;
        SGShape shape = removeShapes.get(size - 1);
        removeShapes.remove(shape);
        shapes.add(shape);
    }

    public void undo(){
        int size = shapes.size();
        if(size == 0) return;
        SGShape shape = shapes.get(size - 1);
        shapes.remove(shape);
        removeShapes.add(shape);
    }

    public void clear(){
        shapes.clear();
        removeShapes.clear();
    }


    private SGShape isLine(List<SGPoint> points, float angles[], SGPath path){

        List<SGPoint> vertexes = new ArrayList<SGPoint>();
        vertexes.add(points.get(0));


        for(int i = 1; i<angles.length - 2; i++){

//            Log.i("xielv", "xie lv =  =  "  + angles[i-1]);

            if(Math.abs(angles[i] - angles[i-1]) > 10 && Math.abs(angles[i+1] - angles[i-1]) > 10
                    && Math.abs(angles[i+2] - angles[i-1]) > 10){

                if(vertexes.size() != 0){
                    SGPoint lastVertex = vertexes.get(vertexes.size()-1);
                    if(points.get(i-1).getX() != lastVertex.getX() &&
                            points.get(i-1).getY() != lastVertex.getY()){
                        vertexes.add(points.get(i));
                    }
                }else{
                    vertexes.add(points.get(i));
                }

            }

        }

        vertexes.add(points.get(points.size()-1));

        SGShape shape = new SGLine(points, path, vertexes);

        return shape;
    }

    private SGShape isCircle(List<SGPoint> points, float angles[], SGPath path){

        float dis_origin_terminal = Utils.getDisTwoPoints(points.get(0), points.get(points.size()-1));

        if(dis_origin_terminal > 70) return null;

        float times_anticlockwise = 0;
        float times_clockwise = 0;

        for(int i = 1; i<angles.length; i++) {
//            Log.i("hbb", "xielv ==  "  +angles[i]);

            if(angles[i] - angles[i-1] >  -20
                    && angles[i] - angles[i-1] < -3 ) times_anticlockwise ++;

            if(angles[i] - angles[i-1] > 3
                    && angles[i] - angles[i-1] < 20) times_clockwise ++;
        }

        Log.i("hbb", "bili == " + (times_anticlockwise / (float)(angles.length-1)));

        if( (times_anticlockwise / (float)(angles.length-1)) > 0.8f) {

            SGPoint middle = points.get(points.size()/2);
            SGPoint init = points.get(0);

            SGPoint center = new SGPoint( (middle.getX() + init.getX()) /2,  (middle.getY() + init.getY()) /2 );

            float radius = Utils.getDisTwoPoints(init, center);

            Log.i("hbb", "init " + init.getX()+"  "+init.getY() + "    middle  "+middle.getX() + "  "
                    + middle.getY() +  "    " + radius);

            SGShape circle = new SGCircle(points, path, radius,center );



            return circle;
        }

        return null;
    }

    private SGShape isTriangle(List<SGPoint> points, float angles[], SGPath path){

        float dis_origin_terminal = Utils.getDisTwoPoints(points.get(0), points.get(points.size()-1));
        if(dis_origin_terminal > 100) return null;

        List<SGPoint> vertexes = new ArrayList<SGPoint>();
        vertexes.add(points.get(0));


        for(int i = 1; i<angles.length - 2; i++){

//            Log.i("xielv", "xie lv =  =  "  + angles[i-1]);

            if(Math.abs(angles[i] - angles[i-1]) > 10 && Math.abs(angles[i+1] - angles[i-1]) > 10
                    && Math.abs(angles[i+2] - angles[i-1]) > 10){

                if(vertexes.size() != 0){
                    SGPoint lastVertex = vertexes.get(vertexes.size()-1);
                    if(points.get(i-1).getX() != lastVertex.getX() &&
                            points.get(i-1).getY() != lastVertex.getY()){
                        vertexes.add(points.get(i));
                    }
                }else{
                    vertexes.add(points.get(i));
                }

            }

        }

        vertexes.add(points.get(points.size()-1));

        if(vertexes.size() == 4){
            vertexes.remove(vertexes.get(3));

            SGPoint a = vertexes.get(0);
            SGPoint b = vertexes.get(1);
            SGPoint c = vertexes.get(2);

            float a_ = Utils.getDisTwoPoints(a, b);
            float b_ = Utils.getDisTwoPoints(b, c);
            float c_ = Utils.getDisTwoPoints(a, c);

            float x = (a_*a.getX()+b_*b.getX()+c_*c.getX())/(a_+b_+c_);
            float y = (a_*a.getY()+b_*b.getY()+c_*c.getY())/(a_+b_+c_);

            SGPoint core = new SGPoint(x,y);


            SGShape sgTriangle = new SGTriangle(points, path, core, vertexes);

            for(SGShape shape : shapes){

                if(shape instanceof SGCircle){
                    SGCircle circle = (SGCircle) shape;

                    //三角形内切圆
                    float dis = Utils.getDisTwoPoints(circle.getCenter(), sgTriangle.getCore());
//                    Log.i("hbb", "dis = dis = "+dis);
                    if(dis < 10){

//                        float disV = Utils.getDisTwoPoints(circle.getCenter(), sgTriangle.getPoints().get(0)) / circle.getRadius();

                        SGPoint p1 = sgTriangle.getPoints().get(0);
                        SGPoint p2 = sgTriangle.getPoints().get(1);
                        SGPoint p3 = sgTriangle.getPoints().get(2);
                        SGPoint center = circle.getCenter();

                        float s = Utils.getSForTriagle(p1, p2, center);

                        float h = s/Utils.getDisTwoPoints(p1, p2);

                        Log.i("hbb", "bili " + Math.abs(h / circle.getRadius() - 1) );

                        if( Math.abs(h / circle.getRadius() - 1) < 0.3 ){

                            float slope = Utils.getSlope(p2, p3);


                        }

                    }

                }
            }

            return sgTriangle;
        }

        return null;
    }


    private SGShape isQuadrangle(List<SGPoint> points, float angles[], SGPath path){

        float dis_origin_terminal = Utils.getDisTwoPoints(points.get(0), points.get(points.size()-1));
        if(dis_origin_terminal > 100) return null;

        List<SGPoint> vertexes = new ArrayList<SGPoint>();
        vertexes.add(points.get(0));


        for(int i = 1; i<angles.length - 2; i++){

//            Log.i("xielv", "xie lv =  =  "  + angles[i-1]);

            if(Math.abs(angles[i] - angles[i-1]) > 10 && Math.abs(angles[i+1] - angles[i-1]) > 10 && Math.abs(angles[i+2] - angles[i-1]) > 10){

                if(vertexes.size() != 0){
                    SGPoint lastVertex = vertexes.get(vertexes.size()-1);
                    if(points.get(i-1).getX() != lastVertex.getX() &&
                            points.get(i-1).getY() != lastVertex.getY()){
                        vertexes.add(points.get(i));
                    }
                }else{
                    vertexes.add(points.get(i));
                }

            }

        }

        vertexes.add(points.get(points.size()-1));

        if(vertexes.size() == 5){
            vertexes.remove(vertexes.get(4));

            SGShape quadrangle = new SGQuadrangle(points, path, vertexes);


            return quadrangle;
        }

        return null;
    }

    private float[] getAngles(List<SGPoint> points){


        float[] angles = new float[points.size()-1];

        for(int i =1; i<points.size(); i++){
            SGPoint point1 = points.get(i);
            SGPoint point2 = points.get(i-1);
            float dy = point1.getY() - point2.getY();
            float dx = point1.getX() - point2.getX();

            if(dx == 0) dx = 0.3f;
            else if(dx < 0) dx -= 0.1;
            else if(dx > 0) dx += 0.1;

            if(dy == 0) dy = 0.3f;
            else if(dy < 0) dx -= 0.1;
            else if(dy > 0) dx += 0.1;

            double slope = dy / dx;

            angles[i-1] = (float) Math.toDegrees(Math.atan(slope));
        }


        return angles;
    }
}
